home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
MacWorld 1999 January - Disc 2
/
Macworld (1999-01) (Disk 2).dmg
/
Shareware World
/
Comms & Internet
/
HTML and CSS modes
/
HTML and CSS Modes
/
hctsmslShared.tcl
< prev
next >
Wrap
Text File
|
1998-11-01
|
31KB
|
962 lines
## -*-Tcl-*-
# ###################################################################
# HTML and CSS mode - tools for editing Cascading Style Sheets
#
# FILE: "hctsmslShared.tcl"
# created: 97-04-05 18.39.51
# last update: 98-11-01 16.58.27
# Author: Johan Linde
# E-mail: <jl@theophys.kth.se>
# www: <http://bach.theophys.kth.se/~jl/Alpha.html>
#
# Version: 2.1.3 and 1.1
#
# Copyright 1996-1998 by Johan Linde
#
# This software may be used freely, and distributed freely, as long as the
# receiver is not obligated in any way by receiving it.
#
# If you make improvements to this file, please share them!
#
# ###################################################################
##
proc hctsmslShared.tcl {} {}
# A list of URLs, cached, to pick from for insertion
newPref v URLs {} HTML
# Home pages, set the old one if it exists.
if {[info exists homePagePath] && [string length $homePagePath] &&
[info exists HTMLmodeVars(baseURL)] && [string length $HTMLmodeVars(baseURL)]} {
if {![info exists HTMLmodeVars(basePath)]} {set HTMLmodeVars(basePath) ""}
newPref v homePages [list [list [string trimright $homePagePath :] $HTMLmodeVars(baseURL) $HTMLmodeVars(basePath) "index.html"]] HTML
lappend modifiedModeVars {homePages HTMLmodeVars}
} else {
newPref v homePages {} HTML
}
# Carriage return
if {![alpha::package vsatisfies ${alpha::version} 7.1b1]} {
proc HTML::carriageReturn {} {
global indentOnCR mode
if { [isSelection] } { deleteSelection }
insertText "\r"
if {![info exists indentOnCR] || $indentOnCR} {
${mode}::indentLine
if {![is::Whitespace [set pre [getText [lineStart [getPos]] [getPos]]]]} {
regexp {^[ \t]*} $pre white
goto [expr [lineStart [getPos]] + [string length $white]]
}
}
}
} else {
proc HTML::carriageReturn {} {
global indentOnReturn mode
if { [isSelection] } { deleteSelection }
insertText "\r"
if {![info exists indentOnReturn] || $indentOnReturn} {
${mode}::indentLine
if {![is::Whitespace [set pre [getText [lineStart [getPos]] [getPos]]]]} {
regexp {^[ \t]*} $pre white
goto [expr [lineStart [getPos]] + [string length $white]]
}
}
}
}
# Checks if the current position is inside the container ELEM.
proc htmlIsInContainer {elem {pos ""}} {
set exp1 "<${elem}(\[ \t\r\]+\[^<>\]*>|>)"
set exp2 "</${elem}>"
if {$pos == ""} {set pos [getPos]}
if {![catch {search -s -f 0 -r 1 -i 1 -m 0 $exp1 $pos} res1] && $pos > [lindex $res1 1] &&
([catch {search -s -f 0 -r 1 -i 1 -m 0 $exp2 $pos} res2] ||
[lindex $res1 0] > [lindex $res2 0])} {
return 1
}
return 0
}
# Determines the path to the home page folder corresponding to path.
# If none, return empty string.
proc htmlWhichHomeFolder {path} {
global HTMLmodeVars
foreach p $HTMLmodeVars(homePages) {
if {[string match "[lindex $p 0]:*" $path] || [string match "[lindex $p 4]:*" $path]} {return $p}
}
return ""
}
# Determines the path to the include folder corresponding to path.
# If none, return empty string.
proc htmlWhichInclFolder {path} {
global HTMLmodeVars
foreach p $HTMLmodeVars(homePages) {
if {[string match "[lindex $p 0]:*" $path] || [string match "[lindex $p 4]:*" $path]} {return [lindex $p 4]:}
}
return ""
}
proc htmlResolveInclPath {txt path} {
regsub -nocase {^:INCLUDE:} $txt $path txt
return $txt
}
# Escapes certain characters in URLs.
proc htmlURLescape {str {slash 0}} {
set hexa {0 1 2 3 4 5 6 7 8 9 A B C D E F}
set nstr ""
set exp "\[\001- \177-ˇ%<>\"#\?=&;|\\{\\}\\`^"
if {$slash} {append exp "/"}
append exp "\]"
while {[regexp -indices $exp $str c]} {
set asc [text::Ascii [string index $str [lindex $c 0]]]
append nstr [string range $str 0 [expr [lindex $c 0] - 1]]
append nstr % [lindex $hexa [expr $asc / 16]] [lindex $hexa [expr $asc % 16]]
set str [string range $str [expr [lindex $c 1] + 1] end]
}
return "$nstr$str"
}
proc htmlURLescape2 {str} {
set url ""
regexp {[^#]*} $str url
set anchor [string range $str [string length $url] end]
return "[htmlURLescape $url]$anchor"
}
# Translate escaped characters in URLs.
proc htmlURLunEscape {str} {
set hexa {0 1 2 3 4 5 6 7 8 9 A B C D E F}
set nstr ""
while {[regexp -indices {%[0-9A-F][0-9A-F]} $str hex]} {
append nstr [string range $str 0 [expr [lindex $hex 0] - 1]]
append nstr [text::Ascii [expr 16 * [lsearch $hexa [string index $str [expr [lindex $hex 0] + 1]]] \
+ [lsearch $hexa [string index $str [expr [lindex $hex 0] + 2]]]] 1]
set str [string range $str [expr [lindex $hex 1] + 1] end]
}
return "$nstr$str"
}
# Adds a URL or window given as input to cache
proc htmlAddToCache {cache newurl} {
global modifiedModeVars HTMLmodeVars htmlModeIsLoaded
if {$cache == "windows" && [lsearch -exact {_self _top _parent _blank} $newurl] >= 0} {return}
set URLs $HTMLmodeVars($cache)
if {[string length $newurl] && [lsearch -exact $URLs $newurl] < 0} {
set URLs [lsort [lappend URLs $newurl]]
set HTMLmodeVars($cache) $URLs
lappend modifiedModeVars [list $cache HTMLmodeVars]
if {[set l [llength $URLs]] == 1 && [info exists htmlModeIsLoaded]} {htmlEnable$cache on}
if {$l > 75 && [expr $l/10 == $l/10.0]} {
alertnote "The $cache cache is very large. Consider cleaning it up."
}
}
}
# Puts up a window with error text.
proc htmlErrorWindow {errHeader errText {cancelButton 0}} {
set errbox "-t {$errHeader} 100 10 400 25"
set hpos 35
foreach err $errText {
lappend errbox -t $err 10 $hpos 400 [expr $hpos + 15]
incr hpos 20
}
if {$cancelButton} {
lappend errbox -b Cancel 105 [expr $hpos + 20 ] 170 [expr $hpos + 40 ]
}
set val [eval [concat dialog -w 430 -h [expr $hpos + 50 ] \
-b OK 20 [expr $hpos + 20 ] 85 [expr $hpos + 40 ] $errbox]]
return [lindex $val 0]
}
# Caches
proc htmlSaveCache {cache text {type html}} {
global PREFS htmlVersion cssVersion
if {![file exists $PREFS]} {mkdir $PREFS}
if {![file exists $PREFS:HTML]} {mkdir $PREFS:HTML}
set fid [open $PREFS:HTML:$cache w]
puts $fid "#[set ${type}Version]"
puts $fid $text
close $fid
}
proc htmlReadCache {cache {type html}} {
global PREFS htmlVersion cssVersion
if {![file exists $PREFS:HTML:$cache]} {error "No cache."}
set fid [open $PREFS:HTML:$cache r]
gets $fid version
if {![regexp {^#[0-9]+\.[0-9]+$} $version] || $version != "#[set ${type}Version]"} {
close $fid
htmlDeleteCache $cache
error "Wrong version."
}
close $fid
uplevel #0 [list source $PREFS:HTML:$cache]
}
proc htmlDeleteCache {cache} {
global PREFS
catch {removeFile $PREFS:HTML:$cache}
}
#===============================================================================
# File routines
#===============================================================================
# Asks for a file and returns the file name including the relative path from
# current window. For images the width and height are also returned.
proc htmlGetFile {{addtocache 1} {linkFile ""} {errormsg 0}} {
upvar pathToNewFile newFile
# get path to this window.
if {![string length [set this [htmlThisFilePath $errormsg]]]} {return}
# Get the file to link to.
if {$linkFile == "" && [catch {getfile "Select file to link to."} linkFile]} {
return
}
# For htmlLinkToNewFile
set newFile $linkFile
# Get URL for this file?
set link [htmlBASEfromPath $linkFile]
if {[lindex $link 4] == "4"} {
alertnote "You can't link to a file in an include folder."
return
}
if {[lindex $this 4] == "4" && "[lindex $this 0][lindex $this 1]" == "[lindex $link 0][lindex $link 1]"} {
set linkTo ":HOMEPAGE:[lindex $link 2]"
} elseif {[lindex $this 0] == [lindex $link 0]} {
set linkTo [htmlRelativePath "[lindex $this 1][lindex $this 2]" "[lindex $link 1][lindex $link 2]"]
} else {
set linkTo [join [lrange $link 0 2] ""]
}
set widthheight ""
if {![file isdirectory $linkFile]} {
# Check if image file.
getFileInfo $linkFile arr
if {$arr(type) == "GIFf"} {
set widthheight [htmlGIFWidthHeight $linkFile]
} elseif {$arr(type) =="JPEG" || $arr(type) == "JFIF"} {
set widthheight [htmlJPEGWidthHeight $linkFile]
}
} else {
append linkTo /
}
# Add URL to cache
if {$addtocache} {htmlAddToCache URLs $linkTo}
return [list $linkTo $widthheight]
}
# Returns the URL to the current window.
proc htmlThisFilePath {errorMsg} {
set thisFile [stripNameCount [lindex [winNames -f] 0]]
# Look for BASE element.
if {![catch {search -s -f 1 -r 1 -i 1 -m 0 {<BASE[ \t\r]+[^>]*>} 0} res]} {
set comm 0
set commPos 0
while {![catch {search -s -f 1 -r 0 -m 0 -l [lindex $res 0] {<!--} $commPos} cres]} {
set comm 1
if {![catch {search -s -f 1 -r 0 -m 0 -l [lindex $res 0] -- {-->} [expr [lindex $cres 1] + 1]} cres]} {
set comm 0
set commPos [lindex $cres 1]
} else {
break
}
}
if {!$comm && [regexp -nocase {HREF=\"?([^ \t\r\">]+)} [getText [lindex $res 0] \
[lindex $res 1]] dum href]} {
if {[catch {htmlBASEpieces $href} basestr]} {
alertnote "Window contains invalid BASE element. Ignored."
} else {
return $basestr
}
}
}
# Check if window is saved.
if {![file exists $thisFile]} {
switch $errorMsg {
0 {
set etxt "You must save the window. If you save, you will then be prompted\
for a file to link to."
}
1 {
set etxt "You must save the window, otherwise it cannot be determined\
where the link is pointing."
}
2 {
set etxt "You must save the window, otherwise the link cannot be determined."
}
3 {
set etxt "You must save the window, otherwise it cannot be determined\
where the links are pointing."
}
4 {
set etxt "You must save the window, otherwise it cannot be determined\
where to upload it."
}
}
if {[lindex [dialog -w 400 -h 100 -t $etxt 10 10 390 60 \
-b Save 20 70 85 90 \
-b Cancel 110 70 175 90] 1]} {
return
}
if {![catch {saveAs "Untitled.html"}]} {
set thisFile [stripNameCount [lindex [winNames -f] 0]]
} else {
return
}
}
return [htmlBASEfromPath $thisFile]
}
# Returns URL to file.
proc htmlBASEfromPath {path} {
global HTMLmodeVars
foreach p $HTMLmodeVars(homePages) {
if {(![set i 0] && [string match "[lindex $p $i]:*" "$path:"]) ||
([llength $p] == 5 && [set i 4] && [string match "[lindex $p $i]:*" "$path:"])} {
set path [string range $path [expr [string length [lindex $p $i]] + 1] end]
regsub -all {:} $path {/} path
return [list [lindex $p 1] [lindex $p 2] $path [lindex $p 0] $i [lindex $p 4]]
}
}
regsub -all {:} $path {/} path
return [list "file:///" "" $path "" 0]
}
# Splits a BASE URL in pieces.
# NOTE! That this proc returns a shorter list than the proc above, is used in
# HTML::DblClick to determine if the doc contains a BASE tag.
proc htmlBASEpieces {href} {
if {[regexp -indices {://} $href css]} {
if {[set sl [string first / [string range $href [expr [lindex $css 1] + 1] end]]] >=0} {
set base [string range $href 0 [expr [lindex $css 1] + $sl + 1]]
set path [string range $href [expr [lindex $css 1] + $sl + 2] end]
set sl [string last / $path]
set epath [string range $path [expr $sl + 1] end]
set path [string range $path 0 $sl]
} else {
set base [string range $href 0 [lindex $css 1]]
set path ""
set epath [string range $href [expr [lindex $css 1] + 1] end]
}
return [list [htmlURLunEscape $base] [htmlURLunEscape $path] [htmlURLunEscape $epath] ""]
} else {
error "Invalid BASE."
}
}
# Determines width and height of a GIF file.
proc htmlGIFWidthHeight {fil} {
if {[catch {open $fil r} fid]} {return}
seek $fid 6 start
set width [expr [htmlReadOne $fid] + 256 * [text::Ascii [read $fid 1]]]
set height [expr [htmlReadOne $fid] + 256 * [text::Ascii [read $fid 1]]]
close $fid
return [list $width $height]
}
# Extracts width and height of a jpeg file.
# Algorithm from the perl script 'wwwimagesize' by
# Alex Knowles, alex@ed.ac.uk
# Andrew Tong, werdna@ugcs.caltech.edu
proc htmlJPEGWidthHeight {fil} {
if {[catch {open $fil r} fid]} {return}
if {[text::Ascii [read $fid 1]] != 255 || [text::Ascii [read $fid 1]] != 216} {return}
set ch ""
while {![eof $fid]} {
while {[text::Ascii $ch] != 255 && ![eof $fid]} {set ch [read $fid 1]}
while {[text::Ascii $ch] == 255 && ![eof $fid]} {set ch [read $fid 1]}
if {[set asc [text::Ascii $ch]] >= 192 && $asc <= 195} {
seek $fid 3 current
set height [expr 256 * [text::Ascii [read $fid 1]] + [htmlReadOne $fid]]
set width [expr 256 * [text::Ascii [read $fid 1]] + [htmlReadOne $fid]]
close $fid
return [list $width $height]
} else {
set ln [expr 256 * [text::Ascii [read $fid 1]] + [text::Ascii [read $fid 1]] - 2]
if {$ln < 0} {break}
seek $fid $ln current
}
}
close $fid
}
# Reads one character from an image file.
# For some mysterious reason 10 and 13 has to be swapped.
proc htmlReadOne {fid} {
set c [text::Ascii [read $fid 1]]
if {$c == 13} {
set c 10
} elseif {$c == 10} {
set c 13
}
return $c
}
# Returns toFile including relative path from fromFile.
proc htmlRelativePath {fromFile toFile} {
# Remove trailing /file from fromFile
set fromFile [string range $fromFile 0 [expr [string last / $fromFile] - 1]]
set fromdir [split $fromFile /]
set todir [split $toFile /]
# Remove the common path.
set i 0
while {[llength $fromdir] > $i && [llength $todir] > $i \
&& [lindex $fromdir $i] == [lindex $todir $i]} {
incr i
}
# Insert ../
foreach f [lrange $fromdir $i end] {
append linkTo "../"
}
# Add the path.
append linkTo [join [lrange $todir $i end] /]
return $linkTo
}
# Determine the path to the file "linkTo", as linked from "base path epath".
proc htmlPathToFile {base path epath hpPath linkTo} {
global HTMLmodeVars
# Expand links in include files.
regsub -nocase {^:HOMEPAGE:} $linkTo "$base$path" linkTo
# Is this a mailto or news URL or anchor?
if {[regexp {^(mailto:|news:|javascript:)} [string tolower $linkTo]]} {error $linkTo}
# remove /file from epath
set sl [string last / $epath]
set efil [string range $epath [expr $sl + 1] end]
set epath [string range $epath 0 $sl]
# anchor points to efil
if {[string index $linkTo 0] == "#"} {set linkTo $efil}
# Remove anchor from "linkTo".
regexp {[^#]*} $linkTo linkTo
# Remove ./ from path
if {[string range $linkTo 0 1] == "./"} {set linkTo [string range $linkTo 2 end]}
# Relative URL beginning with / is relative to server URL.
if {[string index $linkTo 0] == "/"} {
set linkTo "$base[string range $linkTo 1 end]"
}
# Relative URL?
if {![regexp {://} $linkTo]} {
set fromPath [split [string trimright "${path}$epath" /] /]
set toPath [split $linkTo /]
# Back down for every ../
set i 0
foreach tp $toPath {
if {$tp == ".."} {
incr i
} else {
break
}
}
if {$i > [llength $fromPath] } {
error ""
} else {
set path1 [join [lrange $fromPath 0 [expr [llength $fromPath] - $i - 1]] /]
if {[string length $path1]} {append path1 /}
append path1 [join [lrange $toPath $i end] /]
if {[string match "$path*" $path1] && [string length $hpPath]} {
set pathTo [string range $path1 [string length $path] end]
regsub -all {/} $pathTo {:} pathTo
set casePath $pathTo
set pathTo "$hpPath:$pathTo"
if {![file isdirectory $pathTo]} {return [list $pathTo $casePath]}
} elseif {$base == "file:///"} {
regsub -all {/} $path1 {:} pathTo
return [list $pathTo $pathTo]
}
set linkTo "$base$path1"
}
}
foreach hp [concat $HTMLmodeVars(homePages) {{"" file:/// "" ""}}] {
if {[string match "[lindex $hp 1][lindex $hp 2]*" $linkTo] ||
[string trimright "[lindex $hp 1][lindex $hp 2]" /] == $linkTo} {
set pathTo [string range $linkTo [string length "[lindex $hp 1][lindex $hp 2]"] end]
regsub -all {/} $pathTo {:} pathTo
set casePath $pathTo
set pathTo [string trimleft "[lindex $hp 0]:$pathTo" :]
# If link to folder, add default file.
if {[file isdirectory $pathTo]} {
set pathTo [string trimright $pathTo :]
append pathTo ":[lindex $hp 3]"
set casePath [string trimright $casePath :]
append casePath ":[lindex $hp 3]"
}
return [list $pathTo [string trimleft $casePath :]]
}
}
error $linkTo
}
#===============================================================================
# Cmd-Double-click
#===============================================================================
proc HTML::DblClick {from to} {
global htmlURLAttr mode
global ${mode}modeVars filepats
# Build regular expressions with URL attrs.
if {$mode == "HTML"} {
set exp "("
foreach attr $htmlURLAttr {
append exp "$attr|"
}
set exp [string trimright $exp |]
append exp ")(\"\[^\">\]+\"|\[^ \\t\\n\\r>\]+)"
}
set expcss {(url)\(\"?([^\"\)]+)\"?\)}
# Check if user clicked on a link.
if {($mode == "HTML" && ![catch {search -s -f 0 -r 1 -i 1 -m 0 $exp $from} res] && [lindex $res 1] > $from) ||
(![set curl [catch {search -s -f 0 -r 1 -i 1 -m 0 $expcss $from} res]] && [lindex $res 1] > $from)} {
# Get path to this window.
if {![string length [set thisURL [htmlThisFilePath 1]]]} {return}
# Get path to link.
if {[info exists curl]} {set exp $expcss}
regexp -nocase $exp [eval getText $res] dum1 dum2 linkTo
set linkTo [htmlURLunEscape [string trim $linkTo \"]]
# Anchors points to file itself if no BASE. (No BASE if [llength $thisURL] > 4)
if {[string index $linkTo 0] == "#" && [llength $thisURL] > 4} {
if {![catch {search -s -f 1 -r 1 -i 1 -m 0 \
"<(A|MAP)\[ \t\r\n\]+\[^>\]*NAME=\"?[string range $linkTo 1 end]\"?(>|\[ \t\r\n\]+\[^>\]*>)" 0} anc]} {
goto [lindex $anc 0]
insertToTop
}
return
}
if {[catch {lindex [htmlPathToFile [lindex $thisURL 0] [lindex $thisURL 1] [lindex $thisURL 2] [lindex $thisURL 3] $linkTo] 0} linkToPath]} {
if {$linkToPath == ""} {
message "Link not well-defined."
} else {
message "Link points to $linkToPath. Doesn't map to a file on the disk."
}
return
}
# Does the file exist?
if {[file exists $linkToPath] && ![file isdirectory $linkToPath]} {
# Is it a text file?
if {[getFileType $linkToPath] == "TEXT"} {
edit -c $linkToPath
if {[regexp {[^#]*#(.+)$} $linkTo dum anchor] && ![catch {search -s -f 1 -r 1 -i 1 -m 0 \
"<(A|MAP)\[ \t\r\n\]+\[^>\]*NAME=\"?$anchor\"?(>|\[ \t\r\n\]+\[^>\]*>)" 0} anc]} {
goto [lindex $anc 0]
insertToTop
}
} elseif {[set ${mode}modeVars(openNonTextFile)] && [getFileType $linkToPath] != "APPL"} {
launchDoc $linkToPath
} else {
message "[file tail $linkToPath] is not a text file."
}
} else {
set isAnHtmlFile 0
set sufficies ""
foreach mm {HTML CSS JScr} {
if {[info exists filepats($mm)]} {set sufficies [concat $sufficies $filepats($mm)]}
}
foreach suffix $sufficies {
if {[string match $suffix $linkToPath]} {set isAnHtmlFile 1}
}
if {(![file exists $linkToPath] && !$isAnHtmlFile) || [file isdirectory $linkToPath] ||
![regexp {[^:]+} $linkToPath disk] || ![file exists $disk:]} {
message "Cannot open [file tail $linkToPath]."
} else {
set htmlFile [file tail $linkToPath]
if {[lindex [dialog -w 350 -h 140 -t "The file '$htmlFile' does not exist.\
Do you want to open a new empty window with this name?\
It will automatically be saved in the right place,\
and if necessary, new folders will be created." 10 10 340 100 \
-b Yes 20 110 85 130 -b No 115 110 180 130] 1]} {return}
# Create a new file and open it.
foreach p [split [file dirname $linkToPath] :] {
append path "$p:"
# make new folders if needed.
if {![file exists $path]} {
mkdir $path
} elseif {![file isdirectory $path]} {
alertnote "Cannot make a new folder '[file tail $path]'.\
There is already a file with the same name."
return
}
}
append path "$htmlFile"
# create an empty file.
set fid [open $path w]
# I suppose it's best to close it, too.
close $fid
edit $path
}
}
} elseif {$mode == "HTML"} {
if {![catch {search -s -f 0 -r 1 -i 1 -m 0 {FILE=\"[^\"]+\"} $from} res] && [lindex $res 1] > $from} {
regexp -nocase {FILE=\"([^\"]+)\"} [eval getText $res] dum fil
set fil [htmlResolveInclPath [htmlUnQuote $fil] [htmlWhichInclFolder [stripNameCount [lindex [winNames -f] 0]]]]
if {[file exists $fil]} {
edit -c $fil
} else {
message "File not found."
}
} elseif {[htmlIsInContainer SCRIPT]} {
global HOME
select $from $to
set word [getText $from $to]
if {[grep "^${word}( |$)" [lindex [glob $HOME:JSreference:index*] 0]] != ""} {
editMark [lindex [glob $HOME:JSreference:JS*] 0] $word -r
}
} elseif {![htmlRevealColor 1]} {
htmlChangeDblClick
}
}
}
#==============================================================================
# Colors
#==============================================================================
# Convert colour names to numbers and vice versa.
# Or brings up a color picker if cmd-doubleClick.
proc htmlRevealColor {{dblClick 0}} {
global htmlColorName htmlColorNumber htmlColorAttr htmluserColors
global htmluserColorname
set searchstring "("
foreach s $htmlColorAttr {
append searchstring "${s}|"
}
# remove last |
set searchstring [string trimright $searchstring |]
append searchstring ")(\"(\[^\"\]*)\"|(\[^ \\t\\r\">\]*))"
set startpos [getPos]
set endpos [selEnd]
set cantfind 0
# find attribute
set f [search -s -f 0 -r 1 -i 1 -n -m 0 $searchstring $startpos]
if {![string length $f] || [lindex $f 1] < $endpos} {
set cantfind 1
}
if {!$cantfind} {
set txt [getText [lindex $f 0] [lindex $f 1]]
regexp -indices -nocase $searchstring $txt a b c
set cpos [expr [lindex $f 0] + [lindex $c 0]]
set epos [expr [lindex $f 0] + [lindex $c 1] + 1]
set col [string trim [string range $txt [lindex $c 0] [lindex $c 1]] \"]
if {!$dblClick} {
if {[info exists htmlColorName($col)]} {
replaceText $cpos $epos "\"$htmlColorName($col)\""
} elseif {[info exists htmlColorNumber($col)]} {
replaceText $cpos $epos "\"$htmlColorNumber($col)\""
} elseif {[info exists htmluserColorname($col)]} {
replaceText $cpos $epos "\"$htmluserColorname($col)\""
} elseif {[info exists htmluserColors($col)]} {
replaceText $cpos $epos "\"$htmluserColors($col)\""
} else {
beep
message "Don't recognize color."
}
} else {
if {[set ncol [htmlCheckColorNumber $col]] != "0"} {
set ncol [htmlHexColor $ncol]
} else {
set ncol {65535 65535 65535}
}
set newcolor [eval [concat colorTriple {{Change color}} $ncol]]
if {[string length $newcolor]} {
replaceText $cpos $epos "\"[htmlColorHex $newcolor]\""
}
return 1
}
} elseif {!$dblClick} {
beep
message "Current position is not at a color attribute."
} else {
return 0
}
}
# Dialog to handle colors.
proc htmlColors {} {
global htmluserColors
set this ∞
while {1} {
set colors [lsort [array names htmluserColors]]
set box "-t {Colors:} 10 10 80 30 \
-t Number: 10 50 80 70 \
-b Done 10 100 75 120 -b New… 90 100 155 120 -b {New by number…} 250 10 375 30"
if {[llength $colors]} {
append box " -m [list [concat [list $this] $colors]] 90 10 230 30"
append box " -b Change… 168 100 237 120 -b Remove 250 100 315 120 \
-b {Change number…} 250 40 375 60 -b View… 250 70 315 90"
foreach c $colors {
lappend box -n $c -t $htmluserColors($c) 90 50 160 90
}
} else {
append box " -m {{None defined} {None defined}} 90 10 230 30"
}
set values [eval [concat dialog -w 380 -h 130 $box]]
set this [lindex $values 3]
if {[lindex $values 0]} {
return
} elseif {[lindex $values 1]} {
set newc [htmlAddNewColor]
if {[string length $newc]} {set this $newc}
} elseif {[lindex $values 2]} {
set newc [htmlNameColor "" "Color saved." "" ""]
if {[string length $newc]} {set this $newc}
} elseif {[lindex $values 4]} {
set newcolor [eval [concat colorTriple [list $this] [htmlHexColor $htmluserColors($this)]]]
if {![string length $newcolor]} {continue}
set newc [htmlNameColor [htmlColorHex $newcolor] "Color changed." $this $htmluserColors($this)]
if {[string length $newc]} {set this $newc}
} elseif {[lindex $values 5]} {
if {[askyesno "Remove $this?"] == "yes"} {
htmlColordelete $this $htmluserColors($this)
message "Color removed."
}
} elseif {[lindex $values 6]} {
set newc [htmlNameColor "" "Color changed." $this $htmluserColors($this)]
if {[string length $newc]} {set this $newc}
} else {
eval [concat colorTriple [list $this] [htmlHexColor $htmluserColors($this)]]
}
}
}
# Checks if colornumber is identical to another colour.
proc htmlColorIdentical {colornumber changeColor} {
global htmlColorNumber htmluserColorname
if {( ![catch {set colTest $htmlColorNumber($colornumber)}] || \
![catch {set colTest $htmluserColorname($colornumber)}] ) && \
$colTest != $changeColor} {
alertnote "This color is identical with '$colTest'. Two identical \
colors cannot be defined."
return 1
}
return 0
}
# Converts a red green blue number to hex.
proc htmlColorHex {color} {
set hexa {A B C D E F}
set red [expr [lindex $color 0] / 256]
set green [expr [lindex $color 1] / 256]
set blue [expr [lindex $color 2] / 256]
set cols [list [expr $red / 16] [expr $red % 16] [expr $green / 16] [expr $green % 16] [expr $blue / 16] [expr $blue % 16]]
set colornumber {#}
foreach c $cols {
if {$c > 9} {
set c1 [lindex $hexa [expr $c - 10]]
} else {
set c1 $c
}
append colornumber $c1
}
return $colornumber
}
# Converts a hex number to red green blue.
proc htmlHexColor {number} {
foreach c [split [string range $number 1 end] ""] {
switch $c {
A {set c1 10}
B {set c1 11}
C {set c1 12}
D {set c1 13}
E {set c1 14}
F {set c1 15}
default {set c1 $c}
}
lappend numbers $c1
}
set red [expr [lindex $numbers 0] * 4096 + [lindex $numbers 1] * 256]
set green [expr [lindex $numbers 2] * 4096 + [lindex $numbers 3] * 256]
set blue [expr [lindex $numbers 4] * 4096 + [lindex $numbers 5] * 256]
return [list $red $green $blue]
}
proc htmlAddNewColor {} {
set newcolor [colorTriple "New color"]
if {![string length $newcolor]} {return }
return [htmlNameColor [htmlColorHex $newcolor] "Color saved." "" ""]
}
proc htmlNameColor {colornumber msg changeColor changeNumber} {
global htmluserColors basicColors
set alluserColors [array names htmluserColors]
set noname 1
set picker [string length $colornumber]
set values [list $changeColor $changeNumber]
while {$noname} {
if {!$picker} {
if {[string length $changeColor]} {
set ttt Change
} else {
set ttt New
}
set values [dialog -w 300 -h 150 -t "$ttt color" 50 10 250 30 \
-t "Name:" 10 45 75 65 -e [lindex $values 0] 80 45 290 60 \
-t "Number:" 10 75 75 95 -e [lindex $values 1] 80 75 150 90 \
-b OK 20 120 85 140 -b Cancel 110 120 175 140]
if {[lindex $values 3]} {return}
set colorname [string trim [lindex $values 0]]
set colornumber [string trim [lindex $values 1]]
set coltest [htmlCheckColorNumber $colornumber]
if {$coltest == "0"} {
alertnote "$colornumber is not a valid color number. It should be of the form #RRBBGG."
continue
}
set colornumber $coltest
if {[htmlColorIdentical $colornumber $changeColor]} {return}
} else {
if {[htmlColorIdentical $colornumber $changeColor]} {return}
if {[catch {prompt "Color name" $changeColor} colorname]} {
# cancel
return
}
set colorname [string trim $colorname]
}
if {[lsearch -exact $basicColors $colorname] >= 0} {
alertnote "Predefined color. Choose another name."
} elseif {[string length $colorname]} {
set replace 0
if {[lsearch -exact $alluserColors $colorname] >= 0 && \
$colorname != $changeColor} {
set repl [dialog -w 200 -h 75 -b Cancel 20 40 80 60 \
-b Replace 115 40 175 60 \
-t "Replace $colorname?" 10 10 150 30]
if {[lindex $repl 1] } {
set replace 1
# remove the color first
set oldnumber $htmluserColors($colorname)
htmlColordelete $colorname $oldnumber
}
} else {
set replace 1
}
# add the new color
if {$replace} {
if {[string length $changeColor]} {
htmlColordelete $changeColor $changeNumber
}
set noname 0
htmlColordef $colorname $colornumber
message $msg
}
} else {
alertnote "You must name the color."
}
}
return $colorname
}
proc htmlColordef {colorname colornumber} {
global htmluserColors htmluserColorname
set htmluserColors($colorname) $colornumber
set htmluserColorname($colornumber) $colorname
addArrDef htmluserColors $colorname $colornumber
addArrDef htmluserColorname $colornumber $colorname
}
proc htmlColordelete {colorname colornumber} {
global htmluserColors htmluserColorname
catch {unset htmluserColors($colorname)}
catch {unset htmluserColorname($colornumber)}
removeArrDef htmluserColors $colorname
removeArrDef htmluserColorname $colornumber
}
# Check if a color number is a valid number, or one of the predefined names.
# Returns 0 if not and the color number if it is.
proc htmlCheckColorNumber {color} {
global htmlColorName
set color [string tolower $color]
if {[info exists htmlColorName($color)]} {return $htmlColorName($color)}
if {[string index $color 0] != "#"} {
set color "#${color}"
}
set color [string toupper $color]
if {[string length $color] != 7 || ![regexp {^#[0-9A-F]+$} $color]} {
return 0
} else {
return $color
}
}
#===============================================================================
# Colors for background, text and links
#===============================================================================
proc htmlNewColor {var val } {
global htmlColorName
global htmlColorNumber
set htmlColorName($var) $val
set htmlColorNumber($val) $var
}
htmlNewColor black "#000000"
htmlNewColor silver "#C0C0C0"
htmlNewColor gray "#808080"
htmlNewColor white "#FFFFFF"
htmlNewColor maroon "#800000"
htmlNewColor red "#FF0000"
htmlNewColor purple "#800080"
htmlNewColor fuchsia "#FF00FF"
htmlNewColor green "#008000"
htmlNewColor lime "#00FF00"
htmlNewColor olive "#808000"
htmlNewColor yellow "#FFFF00"
htmlNewColor navy "#000080"
htmlNewColor blue "#0000FF"
htmlNewColor teal "#008080"
htmlNewColor aqua "#00FFFF"
# Remove colors conflicting with the new ones
foreach tmpCol [array names htmluserColors] {
if {[info exists htmlColorName($tmpCol)]} {
htmlColordelete $tmpCol $htmluserColors($tmpCol)
}
}
foreach tmpCol [array names htmluserColorname] {
if {[info exists htmlColorNumber($tmpCol)]} {
htmlColordelete $htmluserColorname($tmpCol) $tmpCol
}
}
catch {unset tmpCol}
# A list of colours
set basicColors [lsort [array names htmlColorName]]
rename htmlNewColor ""